﻿//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
// Exo² - Tools - Studio/ExefBuilderModule
// Copyright (C) 2007-2008 Samuel Lacroix and Raphaël Legouge
//
// Distributed under GNU General Public License
// See the License folder for details
// http://www.codeplex.com/exo2 (eng)
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ExefBuilderModule
{
        public partial class PhysiologyGeneration : Form
        {
                public PhysiologyGeneration()
                {
                        InitializeComponent();

                        this.ReadyToDisplayMesh = false;
                        this.ReadyToDisplayTetraedre = false;
                        
                        InitializeDisplay();
                        
                }
                
                public void CreatePhysiology()
                {
                        CDLLWrapper.CreatePhysiologyGenerator();
                        CDLLWrapper.CreateNotifier();
                        CDLLWrapper.InitializeNotifier(this);
                        CDLLWrapper.SetDllMapperNotifier();
                        CDLLWrapper.CreatePhysiology(this.device.ComPointer, this.physiologyName, this.massOrDensity, this.useMass, this.sourceXFileName, this.saveRecenteredXFile, this.recenteredXFileName);       
                }

                public void ResetForm(string physiologyName, double massOrDensity, Boolean useMass, string sourceXFileName, Boolean saveRecenteredXFile, string recenteredXFileName)
                {
                        this.physiologyName = physiologyName;
                        this.massOrDensity = massOrDensity;
                        this.useMass = useMass;
                        this.sourceXFileName = sourceXFileName;
                        this.saveRecenteredXFile = saveRecenteredXFile;
                        this.recenteredXFileName = recenteredXFileName;
                        
                        this.mesh = SlimDX.Direct3D9.Mesh.FromFile(this.device, this.sourceXFileName, SlimDX.Direct3D9.MeshFlags.DoNotClip);
                        NotifyStatusBar("form reset");
                        this.ReadyToDisplayMesh = true;
                }
                
                private void NotifyStatusBar(string Message)
                {
                        this.toolStripStatusLabel1.Text = Message;
                }
                
                private void NotifyListBox(string Message)
                {
                        this.listBox1.Items.Add(Message);
                }

                //
                // Affichage
                //
                // Données membre utile à l'initialisation de l'affichage
                private SlimDX.Direct3D9.PresentParameters presentParameters;
                private SlimDX.Direct3D9.Direct3D direct3D;
                private SlimDX.Direct3D9.Device device;
                private Boolean deviceLost;
                private double fov;
                private double ratio;
                private SlimDX.Matrix cameraMatrix;
                private SlimDX.Matrix transformMatrix;
                
                private Boolean displayMesh;
                private Boolean displayMeshWireframe;
                private SlimDX.Direct3D9.Mesh mesh;
                
                private string physiologyName;
                private double massOrDensity;
                private Boolean useMass;
                private string sourceXFileName;
                private Boolean saveRecenteredXFile;
                private string recenteredXFileName;
                
                private Boolean displayTetraedre;
                private SlimDX.Direct3D9.VertexBuffer TetraedreVertexBuffer;
                
                private Boolean ReadyToDisplayMesh;
                private Boolean ReadyToDisplayTetraedre;
                
                private SlimDX.Vector3[] SamplingPointList;
                private SlimDX.Vector3[] Delaunay;


                // Initialisation de l'affichage
                private void InitializeDisplay() 
                {
                        // Initialisation de Direct3D
                        this.direct3D = new SlimDX.Direct3D9.Direct3D();                // Si ça plante ici sous vista c'est que DirectX9 n'est pas installé...

                        // Choix de l'adapteur de rendu
                        SlimDX.Direct3D9.AdapterInformation adapter = this.direct3D.Adapters.DefaultAdapter;
                        int adapterIndex = adapter.Adapter;

                        // Choix du type de device
                        SlimDX.Direct3D9.DeviceType deviceType = SlimDX.Direct3D9.DeviceType.Hardware;

                        // Choix de la zone de rendu
                        IntPtr handle = this.pictureBox1.Handle;

                        // Choix des paramètres de création du device
                        SlimDX.Direct3D9.CreateFlags createFlags = SlimDX.Direct3D9.CreateFlags.HardwareVertexProcessing;
                        this.presentParameters = new SlimDX.Direct3D9.PresentParameters();

                        // Choix des paramètres de rendu
                        this.presentParameters.DeviceWindowHandle = handle;                                         // Rendu dans la picture box
                        this.presentParameters.BackBufferHeight = this.pictureBox1.Height;                          // Taille de la zone de rendu
                        this.presentParameters.BackBufferWidth = this.pictureBox1.Width;
                        this.presentParameters.Windowed = true;                                                     // Mode fenètré
                        this.presentParameters.BackBufferFormat = SlimDX.Direct3D9.Format.X8R8G8B8;                 // Format du backbuffer
                        this.presentParameters.PresentFlags = SlimDX.Direct3D9.PresentFlags.DiscardDepthStencil;    // On vire le Depth et le Stencil buffer à chaque present

                        this.device = new SlimDX.Direct3D9.Device(direct3D, adapterIndex, deviceType, handle, createFlags, presentParameters);
                        
                        // Création de la lumière 0
                        SlimDX.Direct3D9.Light light0 = new SlimDX.Direct3D9.Light();
                        light0.Type = SlimDX.Direct3D9.LightType.Directional;
                        light0.Ambient = new SlimDX.Color4(new SlimDX.Vector4(0.25f, 0.25f, 0.25f, 1.0f));
                        light0.Diffuse = new SlimDX.Color4(new SlimDX.Vector4(0.35f, 0.35f, 0.35f, 1.0f));
                        light0.Direction = new SlimDX.Vector3(-1.0f, -1.0f, 1.0f);
                        light0.Specular = new SlimDX.Color4(new SlimDX.Vector4(1.0f, 1.0f, 1.0f, 1.0f));

                        // Enregistrement dans le device
                        this.device.SetLight(0, light0);

                        // Création de la lumière 1
                        SlimDX.Direct3D9.Light light1 = new SlimDX.Direct3D9.Light();
                        light1.Type = SlimDX.Direct3D9.LightType.Directional;
                        light1.Ambient = new SlimDX.Color4(new SlimDX.Vector4(0.25f, 0.25f, 0.25f, 1.0f));
                        light1.Diffuse = new SlimDX.Color4(new SlimDX.Vector4(0.35f, 0.35f, 0.35f, 1.0f));
                        light1.Direction = new SlimDX.Vector3(1.0f, 0.0f, 1.0f);
                        light1.Specular = new SlimDX.Color4(new SlimDX.Vector4(1.0f, 1.0f, 1.0f, 1.0f));

                        // Enregistrement dans le device
                        this.device.SetLight(1, light1);

                        // Allumage des lumières
                        this.device.EnableLight(0, true);
                        this.device.EnableLight(1, true);

                        // Création de la matrice de projection
                        this.fov = (float)(Math.Sqrt(2.0) / 2.0);
                        this.ratio = ((double)this.pictureBox1.Width) / this.pictureBox1.Height;
                        float znear = 0.01f;
                        float zfar = 10000.0f;
                        SlimDX.Matrix projectionMatrix = SlimDX.Matrix.PerspectiveFovLH((float)this.fov, (float)this.ratio, znear, zfar);

                        // Enregistrement dans le device
                        this.device.SetTransform(SlimDX.Direct3D9.TransformState.Projection, projectionMatrix);
                        
                        // Matrice de la camera
                        this.cameraMatrix = SlimDX.Matrix.LookAtLH(new SlimDX.Vector3(0.0f, 0.0f, -10.0f), new SlimDX.Vector3(0.0f, 0.0f, 0.0f), new SlimDX.Vector3(0.0f, 1.0f, 0.0f));
                        
                        // Matrice de transformation
                        this.transformMatrix = SlimDX.Matrix.Identity;

                        // Renseignement sur l'état du device
                        this.deviceLost = false;
                        
                        // Options d'affichage
                        this.displayMesh = true;
                        this.displayMeshWireframe = true;
                        this.displayTetraedre = false;
                }
                
                // Mise à jour
                private void UpdateScene()
                {
                
                }
                
                // Rendu
                private void RenderScene()
                {
                        this.device.BeginScene();
                        
                        this.device.SetTransform(SlimDX.Direct3D9.TransformState.View, this.cameraMatrix);
                        this.device.SetTransform(SlimDX.Direct3D9.TransformState.World, this.transformMatrix);
                        
                        if (this.displayTetraedre && this.ReadyToDisplayTetraedre)
                        {
                                this.device.VertexFormat = SlimDX.Direct3D9.VertexFormat.Position;
                                this.device.SetStreamSource(0, this.TetraedreVertexBuffer, 0, /*sizeof(un élément du vertex buffer)*/1);
                                this.device.DrawPrimitives(SlimDX.Direct3D9.PrimitiveType.TriangleFan, 0, 3);
                                this.device.DrawPrimitives(SlimDX.Direct3D9.PrimitiveType.TriangleList, 4, 1);
                        }
                        
                        if (this.displayMesh && this.ReadyToDisplayMesh)
                        {
                                if (this.displayMeshWireframe)
                                        this.device.SetRenderState(SlimDX.Direct3D9.RenderState.FillMode, SlimDX.Direct3D9.FillMode.Wireframe);
                                else
                                        this.device.SetRenderState(SlimDX.Direct3D9.RenderState.FillMode, SlimDX.Direct3D9.FillMode.Solid);
                                int i = 0;
                                foreach (SlimDX.Direct3D9.ExtendedMaterial mat in this.mesh.GetMaterials())
                                {
                                        this.device.Material = mat.MaterialD3D;
                                        this.mesh.DrawSubset(i++);
                                }
                        }                        
                        
                        this.device.EndScene();
                }
                
                // Netoyage
                private void Clear()
                {
                        if (this.device.Clear(SlimDX.Direct3D9.ClearFlags.Target | SlimDX.Direct3D9.ClearFlags.ZBuffer, 0x00000000, 1.0f, 0) == SlimDX.Direct3D9.ResultCode.DeviceLost)
                            this.deviceLost = true;
                }
                
                // Affichage
                private void Present()
                {
                        if (this.device.Present() == SlimDX.Direct3D9.ResultCode.DeviceLost)
                            this.deviceLost = true;
                }

                // Boucle de l'affichage
                public void Run()
                {
                        if (this.deviceLost)
                        {
                                SlimDX.Result Hr = this.device.TestCooperativeLevel();

                                if (Hr.Code == SlimDX.Direct3D9.ResultCode.DeviceLost.Code)
                                {
                                        return;
                                }
                                else
                                {
                                        if (Hr.Code == SlimDX.Direct3D9.ResultCode.DeviceNotReset.Code)
                                        {
                                                this.presentParameters.BackBufferWidth = this.pictureBox1.Width;
                                                this.presentParameters.BackBufferHeight = this.pictureBox1.Height;

                                                this.device.Reset(this.presentParameters);

                                                return;
                                        }
                                        else
                                        {
                                                return;
                                        }
                                }
                        }
                        else
                        {
                                try
                                {
                                        UpdateScene();
                                        Clear();
                                        RenderScene();
                                        Present();
                                }
                                catch (SlimDX.SlimDXException E)
                                {
                                	
                                }
                        }
                }

                private void timer1_Tick(object sender, EventArgs e)
                {
                        if (this.ReadyToDisplayMesh || this.ReadyToDisplayTetraedre)
                            Run();
                }

                public void BeforeLoadSourceXFile(IntPtr SourceXFileName, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FacesNumber, IntPtr pDevice, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances, Int32 pNumMaterials, IntPtr ppMesh)
                {
                        NotifyStatusBar("Loading source X file...");
                        string SourceFileName = Marshal.PtrToStringUni(SourceXFileName);
                        NotifyListBox("> Loading source X file :");
                        NotifyListBox("\tLoading " + SourceFileName);
                }
                public void AfterLoadSourceXFile(IntPtr SourceXFileName, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FacesNumber, IntPtr pDevice, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances, Int32 pNumMaterials, IntPtr ppMesh)
                {
                        NotifyStatusBar("Source X file loaded.");
                        NotifyListBox("\tSource X file loaded.");
                }
                public void BeforeComputeBoundingSphere(IntPtr pEdges, Int32 EdgesNumber, double XCenter, double YCenter, double ZCenter, double Radius)
                {
                        NotifyStatusBar("Computing bounding sphere...");
                        NotifyListBox("> Computing bounding sphere...");
                }
                public void AfterComputeBoundingSphere(IntPtr pEdges, Int32 EdgesNumber, double XCenter, double YCenter, double ZCenter, double Radius)
                {
                        NotifyStatusBar("Bounding sphere computed.");
                        NotifyListBox("\tBounding sphere computed :");
                        NotifyListBox("\tCenter (" + XCenter + ", " + YCenter + ", " + ZCenter + ")");
                        NotifyListBox("\tRadius : " + Radius);
                }
                public void BeforeMoveData(double XDelta, double YDelta, double ZDelta, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FaceNumber, IntPtr ppMesh)
                {
                        NotifyStatusBar("Moving data...");
                        NotifyListBox("> Moving data :");
                }
                public void AfterMoveData(double XDelta, double YDelta, double ZDelta, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FaceNumber, IntPtr ppMesh)
                {
                        NotifyStatusBar("Data moved.");
                        NotifyListBox("\tData moved.");
                        NotifyListBox("\tDelta : (" + XDelta + ", " + YDelta + ", " + ZDelta + ")");
                }
                public void BeforeSaveRecenteredXFile(IntPtr TargetXFileName, IntPtr pMesh, IntPtr Adjacency, IntPtr Materials, IntPtr EffectInstances, Int32 NumMaterials)
                {
                        NotifyStatusBar("Saving recentered X file...");
                        string TargetFileName = Marshal.PtrToStringUni(TargetXFileName);
                        NotifyListBox("> Saving recentered X file :");
                        NotifyListBox("\tFile : " + TargetFileName);
                }
                public void AfterSaveRecenteredXFile(IntPtr TargetXFileName, IntPtr pMesh, IntPtr Adjacency, IntPtr Materials, IntPtr EffectInstances, Int32 NumMaterials)
                {
                        NotifyStatusBar("Recentered X file saved.");
                        NotifyListBox("\tRecentered X file saved.");
                }
                public void BeforeReleaseXFileData(IntPtr ppMesh, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances)
                {
                        NotifyStatusBar("X file data releasing...");
                        NotifyListBox("> X file data releasing...");
                }
                public void AfterReleaseXFileData(IntPtr ppMesh, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances)
                {
                        NotifyStatusBar("X file data released.");
                        NotifyListBox("\tX file data released.");
                }
                public void BeforeGenerateSamplingPoint(IntPtr Edges, Int32 EdgesNumber, IntPtr Faces, Int32 FacesNumber, IntPtr SamplingPoints, Int32 SamplingPointsNumber)
                {
                        NotifyStatusBar("Generate sampling points...");
                        NotifyListBox("> Generate sampling points...");
                }
                public void AfterGenerateSamplingPoint(IntPtr Edges, Int32 EdgesNumber, IntPtr Faces, Int32 FacesNumber, IntPtr SamplingPoints, Int32 SamplingPointsNumber)
                {
                        this.SamplingPointList = new SlimDX.Vector3[SamplingPointsNumber];
                        for (int i = 0; i < SamplingPointsNumber; ++i)
                            this.SamplingPointList[i] = CDLLWrapper.GetVector(CDLLWrapper.GetVector(SamplingPoints, i));
                        NotifyStatusBar("Sampling points generated.");
                        NotifyListBox("\tSampling points generated : ");
                        NotifyListBox("\t" + SamplingPointsNumber + " points generated");
                }
                public void BeforeGenerateDelaunay(double BoundingSphereRadius, IntPtr SamplingPoints, Int32 SamplingPointsNumber, IntPtr pMesh, IntPtr pDelaunay, Int32 TetraedreNumber)
                {
                        NotifyStatusBar("Delaunay generation...");
                        NotifyListBox("> Delaunay generation...");
                }
                public void AfterGenerateDelaunay(double BoundingSphereRadius, IntPtr SamplingPoints, Int32 SamplingPointsNumber, IntPtr pMesh, IntPtr pDelaunay, Int32 TetraedreNumber)
                {
                        this.Delaunay = new SlimDX.Vector3[TetraedreNumber * 4];
                        int j = 0;
                        for (int i = 0; i < TetraedreNumber; ++i)
                        {
                                this.Delaunay[j] = CDLLWrapper.GetVector(CDLLWrapper.GetVector(pDelaunay, j));
                                this.Delaunay[j + 1] = CDLLWrapper.GetVector(CDLLWrapper.GetVector(pDelaunay, j + 1));
                                this.Delaunay[j + 2] = CDLLWrapper.GetVector(CDLLWrapper.GetVector(pDelaunay, j + 2));
                                this.Delaunay[j + 3] = CDLLWrapper.GetVector(CDLLWrapper.GetVector(pDelaunay, j + 3));
                                j += 4;
                        }
                        
                        // 12 * tetraedre number * taille d'un tétraedre
                        // car pour un tétraedre on donne les 3 sommets d'une face et il y en a 4 par tétraedre
                        int Size = 12 * TetraedreNumber * Marshal.SizeOf(typeof(SlimDX.Vector3));
                        this.TetraedreVertexBuffer = new SlimDX.Direct3D9.VertexBuffer(this.device, Size, SlimDX.Direct3D9.Usage.DoNotClip, SlimDX.Direct3D9.VertexFormat.Position, SlimDX.Direct3D9.Pool.Default);
                        
                        // Remplissage du vertex buffer
                        this.TetraedreVertexBuffer.Lock(0, Size, SlimDX.Direct3D9.LockFlags.Discard);
                        
                        
                        
                        this.TetraedreVertexBuffer.Unlock();
                        
                        this.ReadyToDisplayTetraedre = true;
                        
                        NotifyStatusBar("Delaunay generated.");
                        NotifyListBox("\tDelaunay generated : ");
                        NotifyListBox("\t" + TetraedreNumber + " tetraedres generated");
                }                
                public void BeforeGenrateSpheresFromDelaunay()
                {
                        NotifyStatusBar("Generating spheres from delaunay...");
                        NotifyListBox("> Generating spheres from delaunay...");
                }
                public void AfterGenrateSpheresFromDelaunay()
                {
                        NotifyStatusBar("Spheres generated from delaunay.");
                        NotifyListBox("\tSpheres generated from delaunay.");
                }
                public void BeforeSortSpheres()
                {
                        NotifyStatusBar("Sphere sorting...");
                        NotifyListBox("> Sphere sorting...");
                }
                public void AfterSortSpheres()
                {
                        NotifyStatusBar("Spheres sorted.");
                        NotifyListBox("\tSpheres sorted.");
                }
                public void BeforeBuildSphereTree()
                {
                        NotifyStatusBar("Sphere tree building...");
                        NotifyListBox("> Sphere tree building...");
                }
                public void AfterBuildSphereTree()
                {
                        NotifyStatusBar("Sphere tree built.");
                        NotifyListBox("\tSphere tree built.");
                }
                public void BeforeComputeDynamicsData(bool UseMass, double MassOrDensity, IntPtr Delaunay, Int32 TetraedreNumber, double Mass, double Density, double M11, double M12, double M13, double M22, double M23, double M33, double Volume)
                {
                        NotifyStatusBar("Dynamics data computing...");
                        NotifyListBox("> Dynamics data computing...");
                }
                public void AfterComputeDynamicsData(bool UseMass, double MassOrDensity, IntPtr Delaunay, Int32 TetraedreNumber, double Mass, double Density, double M11, double M12, double M13, double M22, double M23, double M33, double Volume)
                {
                        NotifyStatusBar("Dynamics data computed.");
                        NotifyListBox("\tDynamics data computed : ");
                        NotifyListBox("\tMass : " + Mass + " kg");
                        NotifyListBox("\tDensity : " + Density + " kg/m^3");
                        NotifyListBox("\tVolume : " + Volume + " m^3");
                        NotifyListBox("\tInertia matrix :");
                        NotifyListBox("\tM11 = " + M11 + " kg.m^2");
                        NotifyListBox("\tM12 = " + M12 + " kg.m^2");
                        NotifyListBox("\tM13 = " + M13 + " kg.m^2");
                        NotifyListBox("\tM22 = " + M22 + " kg.m^2");
                        NotifyListBox("\tM23 = " + M23 + " kg.m^2");
                        NotifyListBox("\tM33 = " + M33 + " kg.m^2");
                }
                public void BeforeWritePhysiology()
                {
                        NotifyStatusBar("Physiology writting...");
                        NotifyListBox("> Physiology writting...");
                }
                public void AfterWritePhysiology()
                {
                        NotifyStatusBar("Physioloy written.");
                        NotifyListBox("\tPhysioloy written.");
                }

                private void PhysiologyGeneration_FormClosing(object sender, FormClosingEventArgs e)
                {
                        this.ReadyToDisplayMesh = false;
                        this.ReadyToDisplayTetraedre = false;
                }
                                                
        }
        
        class CDLLWrapper
        {
                public static void CreatePhysiologyGenerator()
                {
                        pPhysiologyGenerator = NewPhysiologyGenerator();
                }
                
                public static void ReleasePhysiologyGenerator()
                {
                        DeletePhysiologyGenerator(pPhysiologyGenerator);
                }
                
                public static void CreatePhysiology(IntPtr pDevice, string PhysiologyName, double MassOrDensity, Boolean UseMass, string SourceXFileName, Boolean SaveRecenteredXFile, string RecenteredXFileName)
                {
                        IntPtr PhysiologyNameUnmanaged = Marshal.StringToHGlobalUni(PhysiologyName);
                        IntPtr SourceXFileNameUnmanaged = Marshal.StringToHGlobalUni(SourceXFileName);
                        IntPtr RecenteredXFileNameUnmanaged = Marshal.StringToHGlobalUni(RecenteredXFileName);
                        IntPtr pGenerationData = NewGenerationData(PhysiologyNameUnmanaged, MassOrDensity, UseMass, SourceXFileNameUnmanaged, SaveRecenteredXFile, RecenteredXFileNameUnmanaged);
                        IntPtr pPhysiology = NewPhysiology();
                        CreatePhysiology(pPhysiologyGenerator, pGenerationData, pDevice, pPhysiology);
                        
                }
        
                public static void CreateNotifier()
                {
                        pNotifier = NewDllMapperNotifier();
                }
                
                public static void InitializeNotifier(PhysiologyGeneration physioGenerationForm)
                {
                        // Bindage des delegates.
                        // La dll va ainsi lancer les fonctions 'pointées' par les delegates pendant son traitement
                        BeforeLoadSourceXFile = new LoadSourceXFile(physioGenerationForm.BeforeLoadSourceXFile);
                        SetBeforeLoadSourceXFile(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeLoadSourceXFile));
                        AfterLoadSourceXFile = new LoadSourceXFile(physioGenerationForm.AfterLoadSourceXFile);
                        SetAfterLoadSourceXFile(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterLoadSourceXFile));

                        BeforeComputeBoundingSphere = new ComputeBoundingSphere(physioGenerationForm.BeforeComputeBoundingSphere);
                        SetBeforeComputeBoundingSphere(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeComputeBoundingSphere));
                        AfterComputeBoundingSphere = new ComputeBoundingSphere(physioGenerationForm.AfterComputeBoundingSphere);
                        SetAfterComputeBoundingSphere(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterComputeBoundingSphere));

                        BeforeMoveData = new MoveData(physioGenerationForm.BeforeMoveData);
                        SetBeforeMoveData(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeMoveData));
                        AfterMoveData = new MoveData(physioGenerationForm.AfterMoveData);
                        SetAfterMoveData(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterMoveData));

                        BeforeSaveRecenteredXFile = new SaveRecenteredXFile(physioGenerationForm.BeforeSaveRecenteredXFile);
                        SetBeforeSaveRecenteredXFile(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeSaveRecenteredXFile));
                        AfterSaveRecenteredXFile = new SaveRecenteredXFile(physioGenerationForm.AfterSaveRecenteredXFile);
                        SetAfterSaveRecenteredXFile(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterSaveRecenteredXFile));

                        BeforeReleaseXFileData = new ReleaseXFileData(physioGenerationForm.BeforeReleaseXFileData);
                        SetBeforeReleaseXFileData(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeReleaseXFileData));
                        AfterReleaseXFileData = new ReleaseXFileData(physioGenerationForm.AfterReleaseXFileData);
                        SetAfterReleaseXFileData(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterReleaseXFileData));

                        BeforeGenerateSamplingPoint = new GenerateSamplingPoint(physioGenerationForm.BeforeGenerateSamplingPoint);
                        SetBeforeGenerateSamplingPoint(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeGenerateSamplingPoint));
                        AfterGenerateSamplingPoint = new GenerateSamplingPoint(physioGenerationForm.AfterGenerateSamplingPoint);
                        SetAfterGenerateSamplingPoint(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterGenerateSamplingPoint));

                        BeforeGenerateDelaunay = new GenerateDelaunay(physioGenerationForm.BeforeGenerateDelaunay);
                        SetBeforeGenerateDelaunay(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeGenerateDelaunay));
                        AfterGenerateDelaunay = new GenerateDelaunay(physioGenerationForm.AfterGenerateDelaunay);
                        SetAfterGenerateDelaunay(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterGenerateDelaunay));

                        BeforeGenerateSpheresFromDelaunay = new GenerateSpheresFromDelaunay(physioGenerationForm.BeforeGenrateSpheresFromDelaunay);
                        SetBeforeGenerateSpheresFromDelaunay(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeGenerateSpheresFromDelaunay));
                        AfterGenerateSpheresFromDelaunay = new GenerateSpheresFromDelaunay(physioGenerationForm.AfterGenrateSpheresFromDelaunay);
                        SetAfterGenerateSpheresFromDelaunay(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterGenerateSpheresFromDelaunay));

                        BeforeSortSpheres = new SortSpheres(physioGenerationForm.BeforeSortSpheres);
                        SetBeforeSortSpheres(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeSortSpheres));
                        AfterSortSpheres = new SortSpheres(physioGenerationForm.AfterSortSpheres);
                        SetAfterSortSpheres(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterSortSpheres));

                        BeforeBuildSphereTree = new BuildSphereTree(physioGenerationForm.BeforeBuildSphereTree);
                        SetBeforeBuildSphereTree(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeBuildSphereTree));
                        AfterBuildSphereTree = new BuildSphereTree(physioGenerationForm.AfterBuildSphereTree);
                        SetAfterBuildSphereTree(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterBuildSphereTree));

                        BeforeComputeDynamicsData = new ComputeDynamicsData(physioGenerationForm.BeforeComputeDynamicsData);
                        SetBeforeComputeDynamicsData(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeComputeDynamicsData));
                        AfterComputeDynamicsData = new ComputeDynamicsData(physioGenerationForm.AfterComputeDynamicsData);
                        SetAfterComputeDynamicsData(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterComputeDynamicsData));

                        BeforeWritePhysiology = new WritePhysiology(physioGenerationForm.BeforeWritePhysiology);
                        SetBeforeWritePhysiology(pNotifier, Marshal.GetFunctionPointerForDelegate(BeforeWritePhysiology));
                        AfterWritePhysiology = new WritePhysiology(physioGenerationForm.AfterWritePhysiology);
                        SetAfterWritePhysiology(pNotifier, Marshal.GetFunctionPointerForDelegate(AfterWritePhysiology));
                }
                
                public static void ReleaseNotifier()
                {
                        DeleteDllMapperNotifier(pNotifier);
                }

                public static void SetDllMapperNotifier()
                {
                        SetDllMapperNotifier(pPhysiologyGenerator, pNotifier);
                }
                
                public static SlimDX.Vector3 GetVector(IntPtr pVector)
                {
                        double x = GetX(pVector);
                        double y = GetY(pVector);
                        double z = GetZ(pVector);
                        SlimDX.Vector3 V = new SlimDX.Vector3((float)x, (float)y, (float)z);                        
                        return V;
                }
                
                public static IntPtr GetVector(IntPtr pVector, int i)
                {
                        return GetInVector(pVector, i);
                }
        
                // Données membres
                private static IntPtr pPhysiologyGenerator;
                
                private static IntPtr pNotifier;
                
                private delegate void LoadSourceXFile(IntPtr SourceXFileName, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FacesNumber, IntPtr pDevice, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances, Int32 NumMaterials, IntPtr ppMesh);
                private delegate void ComputeBoundingSphere(IntPtr pEdges, Int32 EdgesNumber, double XCenter, double YCenter, double ZCenter, double Radius);
                private delegate void MoveData(double XDelta, double YDelta, double ZDelta, IntPtr pEdges, Int32 EdgesNumber, IntPtr pFaces, Int32 FaceNumber, IntPtr ppMesh);
                private delegate void SaveRecenteredXFile(IntPtr TargetXFileName, IntPtr pMesh, IntPtr Adjacency, IntPtr Materials, IntPtr EffectInstances, Int32 NumMaterials);
                private delegate void ReleaseXFileData(IntPtr ppMesh, IntPtr pAdjacency, IntPtr pMaterials, IntPtr pEffectInstances);
                private delegate void GenerateSamplingPoint(IntPtr Edges, Int32 EdgesNumber, IntPtr Faces, Int32 FacesNumber, IntPtr SamplingPoints, Int32 SamplingPointsNumber);
                private delegate void GenerateDelaunay(double BoundingSphereRadius, IntPtr SamplingPoints, Int32 SamplingPointsNumber, IntPtr pMesh, IntPtr pDelaunay, Int32 TetraedreNumber);
                private delegate void GenerateSpheresFromDelaunay();
                private delegate void SortSpheres();
                private delegate void BuildSphereTree();
                private delegate void ComputeDynamicsData(bool UseMass, double MassOrDensity, IntPtr Delaunay, Int32 TetraedreNumber, double Mass, double Density, double M11, double M12, double M13, double M22, double M23, double M33, double Volume);
                private delegate void WritePhysiology();
                
                private static LoadSourceXFile BeforeLoadSourceXFile;
                private static LoadSourceXFile AfterLoadSourceXFile;
                private static ComputeBoundingSphere BeforeComputeBoundingSphere;
                private static ComputeBoundingSphere AfterComputeBoundingSphere;
                private static MoveData BeforeMoveData;
                private static MoveData AfterMoveData;
                private static SaveRecenteredXFile BeforeSaveRecenteredXFile;
                private static SaveRecenteredXFile AfterSaveRecenteredXFile;
                private static ReleaseXFileData BeforeReleaseXFileData;
                private static ReleaseXFileData AfterReleaseXFileData;
                private static GenerateSamplingPoint BeforeGenerateSamplingPoint;
                private static GenerateSamplingPoint AfterGenerateSamplingPoint;
                private static GenerateDelaunay BeforeGenerateDelaunay;
                private static GenerateDelaunay AfterGenerateDelaunay;
                private static GenerateSpheresFromDelaunay AfterGenerateSpheresFromDelaunay;
                private static GenerateSpheresFromDelaunay BeforeGenerateSpheresFromDelaunay;
                private static SortSpheres BeforeSortSpheres;
                private static SortSpheres AfterSortSpheres;
                private static BuildSphereTree BeforeBuildSphereTree;
                private static BuildSphereTree AfterBuildSphereTree;
                private static ComputeDynamicsData BeforeComputeDynamicsData;
                private static ComputeDynamicsData AfterComputeDynamicsData;
                private static WritePhysiology BeforeWritePhysiology;
                private static WritePhysiology AfterWritePhysiology;
                
#if DEBUG
                private const string dllName = "physiologycreator_Debug.dll";
#else
                private const string dllName = "physiologycreator_Release.dll"
#endif
                // Fonctions C++ mappées
                [DllImport(dllName, EntryPoint = "NewPhysiologyGenerator")]
                private static extern IntPtr NewPhysiologyGenerator();

                [DllImport(dllName, EntryPoint = "DeletePhysiologyGenerator")]
                private static extern void DeletePhysiologyGenerator(IntPtr pGenerator);

                [DllImport(dllName, EntryPoint = "CreatePhysiology")]
                private static extern void CreatePhysiology(IntPtr pGenerator, IntPtr pCreationData, IntPtr pDevice, IntPtr pPhysiology);

                [DllImport(dllName, EntryPoint = "NewGenerationData")]
                private static extern IntPtr NewGenerationData(IntPtr PhysiologyName, double MassOrDensity, bool UseMass, IntPtr SourceXFileName, bool SaveRecenteredXFile, IntPtr RecenteredXFileName);

                [DllImport(dllName, EntryPoint = "NewPhysiology")]
                private static extern IntPtr NewPhysiology();

                [DllImport(dllName, EntryPoint = "SetDllMapperNotifier")]
                private static extern void SetDllMapperNotifier(IntPtr pGenerator, IntPtr pNotifier);
                
                [DllImport(dllName, EntryPoint = "NewDllMapperNotifier")]
                private static extern IntPtr NewDllMapperNotifier();

                [DllImport(dllName, EntryPoint = "DeleteDllMapperNotifier")]
                private static extern void DeleteDllMapperNotifier(IntPtr pNotifier);

                [DllImport(dllName, EntryPoint = "SetBeforeLoadSourceXFile")]
		private static extern void SetBeforeLoadSourceXFile(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterLoadSourceXFile")]
                private static extern void SetAfterLoadSourceXFile(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeComputeBoundingSphere")]
                private static extern void SetBeforeComputeBoundingSphere(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterComputeBoundingSphere")]
                private static extern void SetAfterComputeBoundingSphere(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeMoveData")]
                private static extern void SetBeforeMoveData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterMoveData")]
                private static extern void SetAfterMoveData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeSaveRecenteredXFile")]
                private static extern void SetBeforeSaveRecenteredXFile(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterSaveRecenteredXFile")]
                private static extern void SetAfterSaveRecenteredXFile(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeReleaseXFileData")]
                private static extern void SetBeforeReleaseXFileData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterReleaseXFileData")]
                private static extern void SetAfterReleaseXFileData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeGenerateSamplingPoint")]
                private static extern void SetBeforeGenerateSamplingPoint(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterGenerateSamplingPoint")]
                private static extern void SetAfterGenerateSamplingPoint(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeGenerateDelaunay")]
                private static extern void SetBeforeGenerateDelaunay(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterGenerateDelaunay")]
                private static extern void SetAfterGenerateDelaunay(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeGenerateSpheresFromDelaunay")]
                private static extern void SetBeforeGenerateSpheresFromDelaunay(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterGenerateSpheresFromDelaunay")]
                private static extern void SetAfterGenerateSpheresFromDelaunay(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeSortSpheres")]
                private static extern void SetBeforeSortSpheres(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterSortSpheres")]
                private static extern void SetAfterSortSpheres(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeBuildSphereTree")]
                private static extern void SetBeforeBuildSphereTree(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterBuildSphereTree")]
                private static extern void SetAfterBuildSphereTree(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeComputeDynamicsData")]
                private static extern void SetBeforeComputeDynamicsData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterComputeDynamicsData")]
                private static extern void SetAfterComputeDynamicsData(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetBeforeWritePhysiology")]
                private static extern void SetBeforeWritePhysiology(IntPtr pNotifier, IntPtr pFunction);
                [DllImport(dllName, EntryPoint = "SetAfterWritePhysiology")]
                private static extern void SetAfterWritePhysiology(IntPtr pNotifier, IntPtr pFunction);
                
                [DllImport(dllName, EntryPoint = "GetX")]
                private static extern double GetX(IntPtr pVector);
                [DllImport(dllName, EntryPoint = "GetY")]
                private static extern double GetY(IntPtr pVector);
                [DllImport(dllName, EntryPoint = "GetZ")]
                private static extern double GetZ(IntPtr pVector);
                [DllImport(dllName, EntryPoint = "GetVector")]
                private static extern IntPtr GetInVector(IntPtr pFirst, Int32 i);
        }
}
